/**
 * Integrated Auth Provider
 * Combines Supabase authentication with FastAPI backend integration
 */

import React, { createContext, useContext, useEffect, useState, useCallback } from 'react';
import { User as SupabaseUser } from '@supabase/supabase-js';
import { supabase } from '../lib/supabase';
import { apiClient, type User, handleApiError } from '../lib/api';

// Enhanced Auth Context Type
interface IntegratedAuthContextType {
  // User state
  user: SupabaseUser | null;
  userProfile: User | null;
  loading: boolean;
  initializing: boolean;

  // Auth methods
  signIn: (email: string, password: string, rememberMe?: boolean) => Promise<void>;
  signUp: (userData: {
    email: string;
    password: string;
    full_name: string;
    display_name?: string;
    gdpr_consent: boolean;
    marketing_consent: boolean;
  }) => Promise<void>;
  signOut: () => Promise<void>;
  resetPassword: (email: string) => Promise<void>;

  // Profile management
  updateProfile: (updates: Partial<User>) => Promise<void>;
  updatePaperPreferences: (preferences: User['paper_preferences']) => Promise<void>;
  updateNotificationPreferences: (preferences: User['notification_preferences']) => Promise<void>;
  refreshUserData: () => Promise<void>;

  // Feature access
  hasFeature: (feature: string) => boolean;
  canUseFeature: (feature: string, currentUsage?: number) => boolean;

  // Subscription info
  subscriptionStatus: 'free' | 'premium' | 'academic' | 'institutional';
  isSubscriptionActive: boolean;
}

const IntegratedAuthContext = createContext<IntegratedAuthContextType | undefined>(undefined);

export function useIntegratedAuth() {
  const context = useContext(IntegratedAuthContext);
  if (context === undefined) {
    throw new Error('useIntegratedAuth must be used within an IntegratedAuthProvider');
  }
  return context;
}

interface IntegratedAuthProviderProps {
  children: React.ReactNode;
}

export function IntegratedAuthProvider({ children }: IntegratedAuthProviderProps) {
  const [user, setUser] = useState<SupabaseUser | null>(null);
  const [userProfile, setUserProfile] = useState<User | null>(null);
  const [loading, setLoading] = useState(false);
  const [initializing, setInitializing] = useState(true);

  // Load user profile from FastAPI backend
  const loadUserProfile = useCallback(async (userId: string) => {
    try {
      const response = await apiClient.getUserProfile(userId);
      if (response.success && response.data) {
        setUserProfile(response.data);
      } else {
        console.error('Failed to load user profile:', response.error);
        setUserProfile(null);
      }
    } catch (error) {
      console.error('Error loading user profile:', error);
      setUserProfile(null);
    }
  }, []);

  // Initialize auth state
  useEffect(() => {
    let mounted = true;

    async function initializeAuth() {
      try {
        // Get initial user session from Supabase
        const { data: { user: initialUser } } = await supabase.auth.getUser();
        
        if (mounted) {
          setUser(initialUser);
          if (initialUser) {
            await loadUserProfile(initialUser.id);
          }
        }
      } catch (error) {
        console.error('Error initializing auth:', error);
      } finally {
        if (mounted) {
          setInitializing(false);
        }
      }
    }

    initializeAuth();

    // Set up auth state listener
    const { data: { subscription } } = supabase.auth.onAuthStateChange(
      async (event, session) => {
        if (mounted) {
          const currentUser = session?.user || null;
          setUser(currentUser);
          
          if (event === 'SIGNED_IN' || event === 'TOKEN_REFRESHED') {
            if (currentUser) {
              await loadUserProfile(currentUser.id);
            }
          } else if (event === 'SIGNED_OUT') {
            setUserProfile(null);
          }
        }
      }
    );

    return () => {
      mounted = false;
      subscription.unsubscribe();
    };
  }, [loadUserProfile]);

  // Sign in with email and password
  const signIn = useCallback(async (email: string, password: string, rememberMe = false) => {
    setLoading(true);
    try {
      // First authenticate with Supabase
      const { data, error } = await supabase.auth.signInWithPassword({
        email,
        password
      });

      if (error) throw error;

      // Then authenticate with FastAPI backend
      const backendResponse = await apiClient.login(email, password);
      if (!backendResponse.success) {
        throw new Error(backendResponse.error || 'Backend authentication failed');
      }

      // Note: User profile will be loaded by the auth state change listener
    } catch (error: any) {
      console.error('Sign in error:', error);
      throw new Error(handleApiError(error.message));
    } finally {
      setLoading(false);
    }
  }, []);

  // Sign up with email and password
  const signUp = useCallback(async (userData: {
    email: string;
    password: string;
    full_name: string;
    display_name?: string;
    gdpr_consent: boolean;
    marketing_consent: boolean;
  }) => {
    setLoading(true);
    try {
      // First register with Supabase
      const { data, error } = await supabase.auth.signUp({
        email: userData.email,
        password: userData.password
      });

      if (error) throw error;

      if (data.user) {
        // Then register with FastAPI backend
        const backendResponse = await apiClient.register({
          ...userData,
          user_id: data.user.id
        } as any);

        if (!backendResponse.success) {
          // If backend registration fails, we should clean up Supabase user
          // This would typically be handled by admin functions
          throw new Error(backendResponse.error || 'Backend registration failed');
        }

        // Load user profile
        await loadUserProfile(data.user.id);
      }
    } catch (error: any) {
      console.error('Sign up error:', error);
      throw new Error(handleApiError(error.message));
    } finally {
      setLoading(false);
    }
  }, [loadUserProfile]);

  // Sign out
  const signOut = useCallback(async () => {
    setLoading(true);
    try {
      const { error } = await supabase.auth.signOut();
      if (error) throw error;
      
      // Clear user profile
      setUserProfile(null);
    } catch (error: any) {
      console.error('Sign out error:', error);
      throw new Error(handleApiError(error.message));
    } finally {
      setLoading(false);
    }
  }, []);

  // Reset password
  const resetPassword = useCallback(async (email: string) => {
    setLoading(true);
    try {
      const { error } = await supabase.auth.resetPasswordForEmail(email, {
        redirectTo: `${window.location.origin}/auth/reset-password`
      });
      
      if (error) throw error;
    } catch (error: any) {
      console.error('Reset password error:', error);
      throw new Error(handleApiError(error.message));
    } finally {
      setLoading(false);
    }
  }, []);

  // Update user profile
  const updateProfile = useCallback(async (updates: Partial<User>) => {
    if (!user || !userProfile) throw new Error('No authenticated user');
    
    setLoading(true);
    try {
      // Update profile via FastAPI backend
      const response = await apiClient.updatePaperPreferences(user.id, updates.paper_preferences!);
      
      if (!response.success) {
        throw new Error(response.error || 'Profile update failed');
      }

      // Reload user profile to get updated data
      await loadUserProfile(user.id);
    } catch (error: any) {
      console.error('Update profile error:', error);
      throw new Error(handleApiError(error.message));
    } finally {
      setLoading(false);
    }
  }, [user, userProfile, loadUserProfile]);

  // Update paper preferences
  const updatePaperPreferences = useCallback(async (preferences: User['paper_preferences']) => {
    if (!user) throw new Error('No authenticated user');
    
    setLoading(true);
    try {
      const response = await apiClient.updatePaperPreferences(user.id, preferences);
      
      if (!response.success) {
        throw new Error(response.error || 'Failed to update paper preferences');
      }

      // Update local state
      setUserProfile(prev => prev ? { ...prev, paper_preferences: preferences } : prev);
    } catch (error: any) {
      console.error('Update paper preferences error:', error);
      throw new Error(handleApiError(error.message));
    } finally {
      setLoading(false);
    }
  }, [user]);

  // Update notification preferences  
  const updateNotificationPreferences = useCallback(async (preferences: User['notification_preferences']) => {
    if (!user) throw new Error('No authenticated user');
    
    setLoading(true);
    try {
      const response = await apiClient.updateNotificationPreferences(user.id, preferences);
      
      if (!response.success) {
        throw new Error(response.error || 'Failed to update notification preferences');
      }

      // Update local state
      setUserProfile(prev => prev ? { ...prev, notification_preferences: preferences } : prev);
    } catch (error: any) {
      console.error('Update notification preferences error:', error);
      throw new Error(handleApiError(error.message));
    } finally {
      setLoading(false);
    }
  }, [user]);

  // Refresh user data
  const refreshUserData = useCallback(async () => {
    if (user) {
      await loadUserProfile(user.id);
    }
  }, [user, loadUserProfile]);

  // Feature access helpers
  const hasFeature = useCallback((feature: string): boolean => {
    if (!userProfile) return false;
    
    const subscriptionFeatures = getSubscriptionFeatures(userProfile.subscription_status);
    return subscriptionFeatures[feature] === true || subscriptionFeatures[feature] > 0;
  }, [userProfile]);

  const canUseFeature = useCallback((feature: string, currentUsage = 0): boolean => {
    if (!userProfile) return false;
    
    const subscriptionFeatures = getSubscriptionFeatures(userProfile.subscription_status);
    const featureLimit = subscriptionFeatures[feature];
    
    if (typeof featureLimit === 'boolean') return featureLimit;
    if (featureLimit === -1) return true; // unlimited
    return currentUsage < featureLimit;
  }, [userProfile]);

  // Subscription helpers
  const subscriptionStatus = userProfile?.subscription_status || 'free';
  const isSubscriptionActive = userProfile ? ['premium', 'academic', 'institutional'].includes(subscriptionStatus) : false;

  // Context value
  const contextValue: IntegratedAuthContextType = {
    user,
    userProfile,
    loading,
    initializing,
    signIn,
    signUp,
    signOut,
    resetPassword,
    updateProfile,
    updatePaperPreferences,
    updateNotificationPreferences,
    refreshUserData,
    hasFeature,
    canUseFeature,
    subscriptionStatus,
    isSubscriptionActive
  };

  return (
    <IntegratedAuthContext.Provider value={contextValue}>
      {children}
    </IntegratedAuthContext.Provider>
  );
}

// Helper function to get subscription features
function getSubscriptionFeatures(subscriptionStatus: string): Record<string, boolean | number> {
  const features: Record<string, Record<string, boolean | number>> = {
    free: {
      max_saved_papers: 10,
      max_alerts: 3,
      max_search_queries: 50,
      advanced_search: false,
      api_access: false,
      priority_support: false,
      analytics: false,
      export_capabilities: false,
      bulk_download: false,
      collaboration_features: false,
      custom_categories: false
    },
    premium: {
      max_saved_papers: 1000,
      max_alerts: 50,
      max_search_queries: 1000,
      advanced_search: true,
      api_access: true,
      priority_support: true,
      analytics: true,
      export_capabilities: true,
      bulk_download: true,
      collaboration_features: false,
      custom_categories: true
    },
    academic: {
      max_saved_papers: 500,
      max_alerts: 25,
      max_search_queries: 500,
      advanced_search: true,
      api_access: true,
      priority_support: false,
      analytics: true,
      export_capabilities: true,
      bulk_download: true,
      collaboration_features: true,
      custom_categories: true
    },
    institutional: {
      max_saved_papers: -1, // unlimited
      max_alerts: -1,
      max_search_queries: -1,
      advanced_search: true,
      api_access: true,
      priority_support: true,
      analytics: true,
      export_capabilities: true,
      bulk_download: true,
      collaboration_features: true,
      custom_categories: true
    }
  };

  return features[subscriptionStatus] || features.free;
}

// Custom hooks for specific functionality
export function useRequireAuth() {
  const { user, initializing } = useIntegratedAuth();
  
  useEffect(() => {
    if (!initializing && !user) {
      // Redirect to login
      window.location.href = '/auth/login';
    }
  }, [user, initializing]);
  
  return { user, isAuthenticated: !!user };
}

export function useSubscriptionFeatures() {
  const { userProfile, hasFeature, canUseFeature } = useIntegratedAuth();
  
  return {
    subscriptionStatus: userProfile?.subscription_status || 'free',
    hasFeature,
    canUseFeature,
    features: userProfile ? getSubscriptionFeatures(userProfile.subscription_status) : {}
  };
}

export function usePaperManagement() {
  const { user } = useIntegratedAuth();
  
  const savePaper = useCallback(async (paperId: string, notes?: string) => {
    if (!user) throw new Error('No authenticated user');
    
    const response = await apiClient.savePaper(user.id, paperId, notes);
    if (!response.success) {
      throw new Error(response.error || 'Failed to save paper');
    }
    return response.data;
  }, [user]);

  const unsavePaper = useCallback(async (paperId: string) => {
    if (!user) throw new Error('No authenticated user');
    
    const response = await apiClient.unsavePaper(user.id, paperId);
    if (!response.success) {
      throw new Error(response.error || 'Failed to unsave paper');
    }
    return response.data;
  }, [user]);

  const getSavedPapers = useCallback(async () => {
    if (!user) throw new Error('No authenticated user');
    
    const response = await apiClient.getSavedPapers(user.id);
    if (!response.success) {
      throw new Error(response.error || 'Failed to get saved papers');
    }
    return response.data;
  }, [user]);

  const submitFeedback = useCallback(async (paperId: string, feedbackType: string, feedbackData: any = {}) => {
    if (!user) throw new Error('No authenticated user');
    
    const response = await apiClient.submitFeedback({
      user_id: user.id,
      paper_id: paperId,
      feedback_type: feedbackType as any,
      feedback_data: feedbackData
    });
    
    if (!response.success) {
      throw new Error(response.error || 'Failed to submit feedback');
    }
    return response.data;
  }, [user]);

  return {
    savePaper,
    unsavePaper,
    getSavedPapers,
    submitFeedback
  };
}